home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c-part1 / 4142 < prev    next >
Encoding:
Text File  |  1996-08-05  |  7.3 KB  |  276 lines

  1. Path: beach.and.nl!usenet
  2. From: jos@and.nl (Jos A. Horsmeier)
  3. Newsgroups: comp.lang.c
  4. Subject: Re: Got Questions About Multi-Dimension Arrays (After Reading FAQ)
  5. Date: 1 Feb 1996 11:26:31 GMT
  6. Organization: AND Operations Research B.V.
  7. Distribution: world
  8. Message-ID: <4eq817$icr@beach.and.nl>
  9. References: <4ep87b$o60@alcor.usc.edu>
  10. NNTP-Posting-Host: klepzeiker.and.nl
  11. Mime-Version: 1.0
  12. Content-Type: Text/Plain; charset=ISO-8859-1
  13. X-Newsreader: WinVN 0.99.5
  14.  
  15. In article <4ep87b$o60@alcor.usc.edu>, wawda@alcor.usc.edu wrote:
  16.  
  17. |I read questions 6.19 and 6.20 from the FAQ that deal with
  18. |multi-dimensional arrays but am still confused. If someone can clear
  19. |up my confusion, I would really appreciate it. Bascailly I still don't
  20. |see why it isn't possible to do this:
  21. |
  22. |void myfunc(int *array,int rows,int cols)
  23. |{
  24. |   printf("%d\n",array[1][1]);
  25. |} 
  26. |
  27. |and call the function like this:
  28. |
  29. |int m[2][2] = {1, 2, 3, 4};
  30. |
  31. |myfunc(m,2,2);
  32. |
  33. |If I understand correctly, a multideminsional array is really stored
  34. |continguously like this in memory:
  35. |
  36. |array[0][0]     | 1 | memory address a
  37. |array[0][1]     | 2 | memory address a+sizeof(int)
  38. |array[1][0]     | 3 | ....
  39. |array[1][1]     | 4 | ....
  40. |
  41. |So why can't C convert from pointer to integer to a multidemsional
  42. |array. The reason I want to do this is because my function needs to
  43. |take in an array of any width and height. Thank you for your time,
  44.  
  45. I know, it's confusing; especially if you don't know what's happening
  46. deep down at the bottom. Let's start at the bottom and figure out what's
  47. really going on there:
  48.  
  49.     int i;
  50.  
  51. Object 'i' is declared (and defined) to be an integer object. Whenever
  52. we use 'i', we get back an integral valued object. Here's one step up:
  53.  
  54.     int *ip;
  55.  
  56. Object 'ip' can point to an integer object; I used to explain this as:
  57. 'ip is one star (dereference) away from an int'. If ip points to i:
  58.  
  59.     ip= i;
  60.  
  61. then object ip contains a value and nobody is actually supposed to know
  62. what this value really is; all that suffices is that 'ip points to i'.
  63. The value of object ip is 'one star away of an int', so:
  64.  
  65.     *ip
  66.  
  67. is an int, and because ip happens to point to i, *ip happens to be the
  68. value of i. Let's introduce a bunch of ints:
  69.  
  70.     int ai[A_BUNCH]= { 0, 1, 2, ... A_BUNCH-1 };
  71.  
  72.  
  73. C guarantees that the value of ai is just 'one star away from an int', so:
  74.  
  75.     ai 
  76.  
  77. points to an int, and to be more specific, it points to the first int
  78. of the entire bunch of ints, i.e. it points to ai[0], so:
  79.  
  80.     *ai
  81.  
  82. equals ai[0]. and the statements:
  83.  
  84.     int *ip= ai;
  85.         
  86.     ip++;
  87.     
  88. make ip point to the next int in the bunch, i.e. *ip == ai[1].
  89.  
  90. Let's introduce a lot of bunches of ints:
  91.  
  92.     int aai[A_LOT][A_BUNCH] = { { 0, 1, 2, ... A_BUNH-1 },
  93.                     { A_BUNCH, ... 2*A_BUNCH-1 },
  94.                     ...         ...
  95.                     {   ...        A_LOT*A_BUNCH-1 }
  96.                   };
  97.  
  98. The value of aai is 'one star away from a bunch of ints', i.e. aai
  99. points to the first bunch of ints: aai[0] (the first row of the matrix).
  100.  
  101. Let's get back to your function:
  102.  
  103.     void myfunc(int *array,int rows,int cols)
  104.     {
  105.        printf("%d\n",array[1][1]);
  106.     } 
  107.  
  108. If we call this function as:
  109.  
  110.     myfunc(aai, A_LOT, A_BUNCH);
  111.  
  112. we implicitely cast an object, a 'thing' that points to a bunch of ints
  113. (aai) to an object type that is supposed to point to an int. Remember:
  114.  
  115.     int* array;
  116.  
  117. declares 'array' to be a thing that is 'one star away from an int', 
  118. while 'aai' happens to be 'one star away from a bunch of ints'. 
  119. Now  what is the expression:
  120.  
  121.     array[1][1]
  122.  
  123. supposed to be then? If 'array' is 'one star away from an int' then
  124.  
  125.     array[1]
  126.  
  127. yields a value equal to:
  128.  
  129.     array++;
  130.     *array;
  131.  
  132. So array[1] is an int already; but then, the expression:
  133.  
  134.     array[1][1]
  135.  
  136. must be read as:
  137.  
  138.     <some int value>[1]
  139.  
  140. and this doesn't make sense. Definitely the declaration of the parameter
  141. 'array' is wrong here. We want 'array' not te be 'one star away from an int',
  142. but we want it to 'one star away from a bunch of ints'. Here goes:
  143.  
  144.     void myfunc(int (*array)[A_BUNCH],int rows,int cols)
  145.     {
  146.        printf("%d\n",array[1][1]);
  147.     } 
  148.  
  149. Please note the expicit parentheses here. This declaration reads:
  150.  
  151.     'array' is a pointer ('one star away') from a bunch of ints.
  152.  
  153. Everything seems to be fine now, but there's one disappointment coming
  154. up: we've explicitely told the compiler that object 'array' points to
  155. a bunch of ints and the actual value of 'bunch' is known at compile time,
  156. i.e. to make the examples above work, we need something like:
  157.  
  158.     #define A_BUNCH 42
  159.  
  160. somehwere near the top of the source code file. We cannot supply the 
  161. number of columns, i.e. the value of A_BUNCH, during runtime. C is 
  162. just a silly little language -- it does not support real dynamic arrays.
  163.  
  164. There's a workaround though: we want array[0] point to the first bunch
  165. of ints, array[1] must point to the second bunch, and so on, up till
  166. array[A_LOT-1], which must point to the last bunch of ints and we want
  167. to specify what 'a bunch' and 'a lot' is during runtime. This is where
  168. malloc() and friends come in -- if C is too silly to handle dynamic
  169. arrays, we'll hack 'em together ourselves (isn't that what programming
  170. is all about? ;-) Here goes:
  171.  
  172.     int **array;
  173.  
  174. The object 'array' is 'two stars away from an int', so array[0], array[1],
  175. etc. are 'one star away from an int'.
  176.  
  177. Have a look at this:
  178.  
  179.     array= malloc(A_LOT*sizeof(int*));
  180.  
  181. if malloc succeeds, object 'array' now points a A_LOT of things that
  182. are all 'one star away from an int'. Here's a lot of bunches of ints:
  183.  
  184.     int* temp= malloc(A_LOT*A_BUCH*sizeof(int));
  185.  
  186. and 'temp' (which is not important here, it just exists for the sake of
  187. the example) points to all of them. Let's make all the array[i] objects
  188. point to their own bunch of ints:
  189.  
  190.     int i;
  191.  
  192.     for (i= 0; i < A_LOT; i++)
  193.         array[i]= &(temp[i*A_BUNCH]);
  194.  
  195. This is what happened:
  196.  
  197.     array             0   1   2          A_BUNCH-1
  198.     +---+        +---+---+---+        +---+
  199.       0 |  ------------>|   |   |   | ...... |   |
  200.         +---+           +---+---+---+        +---+
  201.       1 |  ------------>|   |   |   | ...... |   | 
  202.         +---+           +---+---+---+        +---+
  203.          ...             ...          ......  ...
  204.         +---+           +---+---+---+        +---+
  205. A_LOT-1 |  ------------>|   |   |   | ...... |   | 
  206.         +---+           +---+---+---+        +---+
  207.  
  208. And now the expression
  209.  
  210.     array[1][1]
  211.  
  212. points to the second int in the second bunch of ints, because the
  213. expression
  214.  
  215.     array[1]
  216.  
  217. is one star away from a bunch of ints, and the expression
  218.  
  219.     array
  220.  
  221. is one star away from a lot of bunches of ints.
  222.  
  223. We can generalize the above observations and fiddle-diddle the following
  224. function:
  225.  
  226.  
  227.     void* mat_alloc(int rows, int cols, int size) {
  228.  
  229.         char** mat = malloc(rows*sizeof(char*));
  230.         char*  temp= malloc(rows*cols*size);
  231.  
  232.         int    i;
  233.     
  234.         for (i= 0; i < rows; i++)
  235.             mat[i]= &(temp[i*cols]);
  236.  
  237.         return mat;
  238.  
  239.     }    
  240.  
  241. All you have to do now, is:
  242.  
  243.     int** m= mat_alloc(2, 2, sizeof(1));
  244.  
  245. which makes object m 'one star away from two things that are one star away
  246. from two ints', i.e. m[1][1] does exactly what you had in mind. We do have
  247. to change your function a bit though:
  248.  
  249.     void myfunc(int **array,int rows,int cols)
  250.     {
  251.        printf("%d\n",array[1][1]);
  252.     } 
  253.  
  254. (note the two '*'s in the declaration of parameter 'array'). To complete
  255. the example, this is how one gets rid of matrix m again:
  256.  
  257.     void    mat_free(void* mat) {
  258.  
  259.         char**    temp= mat;
  260.  
  261.         if (temp)
  262.             free(*temp);
  263.     
  264.         free(temp);
  265.  
  266.     }
  267.  
  268. Does this help you out a bit?
  269.  
  270. kind regards,
  271.  
  272. Jos aka jos@and.nl
  273. -- 
  274. Atnwgqkrl gy zit vgksr, ug qshiqwtzoeqs!
  275.  
  276.